#ifndef HERM_UTILS_MISC_H
#define HERM_UTILS_MISC_H

#include <string>
#include <fstream>
#include <map>
#include <vector>
#include "herm/export_symbols.h"
#include "exception.h"

#ifdef WIN32
	#pragma warning(disable:4251)

	#define _WINSOCKAPI_
	#define NOMINMAX
	#include <Windows.h>
#endif

#ifndef __cplusplus
	#ifndef nullptr
		#define nullptr (void*)0
	#endif
#else
	#ifndef nullptr
		#define nullptr 0
	#endif
#endif	
	
namespace herm{
/**
 * @brief Herm Assert.
 */
void HERM_API AssertInWindow(bool off, const std::string& expr, const std::string& file, int line);
void HERM_API AssertInConsole(bool off, const std::string& expr, const std::string& file, int line);

std::string HERM_API GetModulePath(const std::string& fileName = std::string(""));
std::string HERM_API GetMouleFile();
bool HERM_API IsPowerOf2(unsigned int x);
unsigned int HERM_API RoundUpPowerOf2(unsigned int x);
void Sleep(int us);

} // end namespace herm{

#define HERM_DELETE(pointer) \
	delete pointer; \
	pointer = nullptr;

#define HERM_DELETE_ARRAY(pointer) \
	delete[] pointer; \
	pointer = nullptr;

#ifdef HERM_NDEBUG
	#define HERM_ASSERT(expr)
#else
	#if (defined WIN32) && (defined _WINDOWS)
		#define HERM_ASSERT(expr) herm::AssertInWindow(expr, #expr, __FILE__, __LINE__)
	#else
		#define HERM_ASSERT(expr) herm::AssertInConsole(expr, #expr, __FILE__, __LINE__)
	#endif // end #if (defined WIN32) && (!defined _CONSOLE)
#endif // end #ifdef HERM_NDEBUG

// Memory Barrier
#if defined(_MSC_VER) && _MSC_VER >= 1310
    #define mb() MemoryBarrier()
	#define rmb() MemoryBarrier()
	#define wmb() MemoryBarrier()
/*
//#elif defined __amd64__
//	#define mb()
//#elif defined __linux__
	// Memory barrier, copy from linux kernel
//	#define __ASM_FORM(x)	" " #x " "
//	#define __ASM_SEL(a,b) __ASM_FORM(a)

//	#define _ASM_ALIGN	__ASM_SEL(.balign 4, .balign 8)
//	#define _ASM_PTR	__ASM_SEL(.long, .quad)
//	#define __stringify_1(x...)	#x
//	#define __stringify(x...)	__stringify_1(x)

//	#define ALTERNATIVE(oldinstr, newinstr, feature)			\
											\
//		  "661:\n\t" oldinstr "\n662:\n"					\
//		  ".section .altinstructions,\"a\"\n"				\
//		  _ASM_ALIGN "\n"							\
//		  _ASM_PTR "661b\n"				\
//		  _ASM_PTR "663f\n"					\
//		  "	 .byte " __stringify(feature) "\n"	\
//		  "	 .byte 662b-661b\n"			\
//		  "	 .byte 664f-663f\n"				\
//		  ".previous\n"							\
//		  ".section .altinstr_replacement, \"ax\"\n"			\
//		  "663:\n\t" newinstr "\n664:\n"		\
//		  ".previous"

//	#define alternative(oldinstr, newinstr, feature) \
//		asm volatile (ALTERNATIVE(oldinstr, newinstr, feature) : : : "memory")

//	#define X86_FEATURE_XMM		(0*32+25) 
//	#define X86_FEATURE_XMM2	(0*32+26) 
															  
//	#define mb() alternative("lock; addl $0,0(%%esp)", "mfence", X86_FEATURE_XMM2)
//	#define rmb() alternative("lock; addl $0,0(%%esp)", "lfence", X86_FEATURE_XMM2)
//	#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)
//    #define mb() __asm__ __volatile__( "" : : : "memory" );
//    #define rmb() __asm__ __volatile__( "" : : : "memory" );
//    #define wmb() __asm__ __volatile__( "" : : : "memory" ); */
#elif defined __FreeBSD__
    #define mb() 
	#define rmb() 
	#define wmb()
#else 
    #define mb() __asm__ __volatile__( "" : : : "memory" );
    #define rmb() __asm__ __volatile__( "" : : : "memory" );
    #define wmb() __asm__ __volatile__( "" : : : "memory" );
#endif // #if defined __linux__

#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()

#endif
